home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / shells / scsh-0.4 / scsh-0 / scsh-0.4.2 / env / debug.scm < prev    next >
Text File  |  1995-10-13  |  16KB  |  576 lines

  1. ; Copyright (c) 1993, 1994 Richard Kelsey and Jonathan Rees.  See file COPYING.
  2.  
  3.  
  4. ; Commands for debugging.
  5.  
  6. ; translate
  7.  
  8. (define-command-syntax 'translate "<from> <to>"
  9.   "establish file name translation"
  10.   '(filename filename))
  11.  
  12. (define translate set-translation!)
  13.  
  14. ; preview  -- show continuations
  15.  
  16. (define (preview)
  17.   (display-preview (continuation-preview (command-continuation))
  18.            (command-output)))
  19.  
  20. (define (display-preview preview port)
  21.   (for-each (lambda (info+pc)
  22.           (if (not (fluid-let-continuation-info? (car info+pc)))
  23.           (display-template-names (car info+pc) port)))
  24.         preview))
  25.  
  26. (define (display-template-names info port)
  27.   (let ((names (debug-data-names info)))
  28.     (display "  " port)
  29.     (if (null? names)
  30.     (begin (display "unnamed " port)
  31.            (write `(id ,(if (debug-data? info)
  32.                 (debug-data-uid info)
  33.                 info))
  34.               port))
  35.     (let loop ((names names))
  36.       (if (car names)
  37.           (write (car names) port)
  38.           (display "unnamed" port))
  39.       (if (and (not (null? (cdr names)))
  40.            (cadr names))
  41.           (begin (display " in " port)
  42.              (loop (cdr names))))))
  43.     (newline port)))
  44.  
  45. (define fluid-let-continuation-info?    ;Incestuous!
  46.   (let ((id (let-fluid (make-fluid #f) #f
  47.           (lambda ()
  48.         (primitive-catch (lambda (k)
  49.                    (template-id
  50.                     (continuation-template k))))))))
  51.     (lambda (info) 
  52.       (eqv? (if (debug-data? info)
  53.         (debug-data-uid info)
  54.         info)
  55.         id))))
  56.  
  57.  
  58. (define-command-syntax 'preview ""
  59.   "show pending continuations (stack trace)"
  60.   '())
  61.  
  62. ; Proceed
  63.  
  64. (define (really-proceed vals)
  65.   (let* ((level (command-level))
  66.      (condition (command-level-condition level)))
  67.     (if (ok-to-proceed? condition)
  68.     (throw-to-command-level
  69.          level
  70.          (lambda ()
  71.            (let ((interrupts (enabled-interrupts))
  72.              (new-interrupts (command-level-interrupts level)))
  73.          (if (not (= new-interrupts interrupts))
  74.              (begin (if (not (and (interrupt? condition)
  75.                       (= (caddr condition) interrupts)))
  76.                 (write-line "(Disabling interrupts)"
  77.                         (command-output)))
  78.                 (set-enabled-interrupts! new-interrupts))))
  79.            (apply values vals)))
  80.     (write-line "No way to proceed from here." (command-output)))))
  81.  
  82. (define-command-syntax 'proceed "<exp>" "proceed after an interrupt or error"
  83.   '(&rest expression))
  84.  
  85. (define (proceed . exps)
  86.   (really-proceed (map (lambda (exp)
  87.              (evaluate exp (environment-for-commands)))
  88.                exps)))
  89.  
  90. ; Scrutinize the condition to ensure that it's safe to return from the
  91. ; call to RAISE.
  92.  
  93. (define (ok-to-proceed? condition)
  94.   (and condition
  95.        (if (error? condition)
  96.        (and (exception? condition)
  97.         (let ((opcode (exception-opcode condition)))
  98.           (or (= opcode op/global)
  99.               (= opcode op/local0)
  100.               (= opcode op/set-global!)
  101.               (>= opcode op/eq?))))
  102.        #t)))
  103.  
  104. (define op/global (enum op global))
  105. (define op/local0 (enum op local0))
  106. (define op/set-global! (enum op set-global!))
  107. (define op/eq? (enum op eq?))
  108.  
  109.  
  110. (define (breakpoint . rest)
  111.   (command-loop unspecific
  112.         (make-condition 'breakpoint rest)))
  113.  
  114. (define-condition-type 'breakpoint '())
  115. (define breakpoint? (condition-predicate 'breakpoint))
  116.  
  117.  
  118. ; push
  119.  
  120. (define-command-syntax 'push "" "push command level" '())
  121.  
  122. (define (push)
  123.   (command-loop list
  124.         (if (command-level? (focus-object))
  125.             (command-level-condition (focus-object))
  126.             #f)))
  127.  
  128. ; reset
  129.  
  130. (define (reset)
  131.   (abort-to-command-level (top-command-level)))
  132.  
  133. (define-command-syntax 'reset "" "top level" '())
  134.  
  135. (define (go-to-level n)
  136.   (let ((levels (reverse (fluid $command-levels))))
  137.     (if (and (integer? n)
  138.          (>= n 0)
  139.          (< n (length levels)))
  140.     (abort-to-command-level (list-ref levels n))
  141.     (write-line "invalid command level" (command-output)))))
  142.  
  143. (define-command-syntax 'level "<number>" "go to specific command level"
  144.   '(expression))
  145.  
  146. (define level go-to-level)
  147.  
  148. (define-command-syntax 'condition ""
  149.   "select an object that describes the current error condition"
  150.   '())
  151.  
  152. (define (condition)
  153.   (let ((c (command-level-condition (command-level))))
  154.     (if c
  155.     (set-focus-object! c)
  156.     (write-line "no condition" (command-output)))))
  157.  
  158. ; Commands that toggle various flags.
  159.  
  160. (define (toggle-command get set description)
  161.   (lambda maybe-option
  162.     (let ((b (if (null? maybe-option)
  163.          (not (get))
  164.          (case (car maybe-option)
  165.            ((off) #f)
  166.            ((on) #t)
  167.            ((?) (get))
  168.            (else (error "invalid setting (should be on or off or ?)"
  169.                 (car maybe-option))))))
  170.       (out (command-output)))
  171.       (set b)
  172.       (display (if b "Will " "Won't ") out)
  173.       (display description out)
  174.       (newline out))))
  175.  
  176. (define syntax-for-toggle '(&opt name))
  177.  
  178.  
  179. ; Batch mode
  180.  
  181. (define-command-syntax 'batch "[on | off]"
  182.   "enable/disable batch mode (no prompt, errors exit)"
  183.   syntax-for-toggle)
  184.  
  185. (define batch
  186.   (toggle-command batch-mode?
  187.           set-batch-mode?!
  188.           "exit on errors"))
  189.  
  190. ; Benchmark mode (i.e., inline primitives)
  191.  
  192. (define-command-syntax 'bench "[on | off]"
  193.   "enable/disable benchmark mode (integrate primitives)"
  194.   syntax-for-toggle)
  195.  
  196. (define bench
  197.   (toggle-command (lambda ()
  198.             (package-integrate? (environment-for-commands)))
  199.           (lambda (b)
  200.             (set-package-integrate?! (environment-for-commands) b))
  201.           "compile some calls in line"))
  202.  
  203. ; Break on warnings
  204.  
  205. (define-command-syntax 'break-on-warnings "[on | off]"
  206.   "treat warnings as errors"
  207.   syntax-for-toggle)
  208.  
  209. (define break-on-warnings
  210.   (toggle-command break-on-warnings?
  211.           set-break-on-warnings?!
  212.           "enter breakpoint on warnings"))
  213.  
  214.  
  215. (define-command-syntax 'form-preferred "[on | off]"
  216.   "enable/disable form-preferred command processor mode"
  217.   syntax-for-toggle)
  218.  
  219. (define form-preferred
  220.   (toggle-command (user-context-accessor 'form-preferred? (lambda () #t))
  221.           (user-context-modifier 'form-preferred?)
  222.           "prefer forms to commands"))
  223.  
  224. (define-command-syntax 'levels "[on | off]"
  225.   "disable/enable command levels"
  226.   syntax-for-toggle)
  227.  
  228. (define levels
  229.   (toggle-command (user-context-accessor 'push-command-levels (lambda () #t))
  230.           (user-context-modifier 'push-command-levels)
  231.           "push command level on errors"))
  232.  
  233.  
  234. ; Flush debug data base
  235.  
  236. (define-command-syntax 'flush "[<kind> ...]"
  237.   "start forgetting debug information
  238. Kind should be one of: names maps files source tabulate
  239.  location-names file-packages"
  240.   '(&rest name))
  241.  
  242. (define (flush . kinds)
  243.   (cond ((null? kinds)
  244.      (write-line "Flushing location names and tabulated debug info"
  245.              (command-output))
  246.      (flush-location-names)
  247.      ((debug-flag-modifier 'table) (make-table)))
  248.     (else
  249.      (for-each (lambda (kind)
  250.              (cond ((memq kind debug-flag-names)
  251.                 ((debug-flag-modifier kind)
  252.                  (if (eq? kind 'table) (make-table) #f)))
  253.                ((eq? kind 'location-names)
  254.                 (flush-location-names))
  255.                ((eq? kind 'file-packages)
  256.                 (forget-file-environments))
  257.                (else
  258.                 (write-line "Unrecognized debug flag"
  259.                     (command-output)))))
  260.            kinds))))
  261.  
  262. ; Control retention of debugging information
  263.  
  264. (define-command-syntax 'keep "[<kind> ...]"
  265.   "start remembering debug information
  266. Kind should be one of: names maps files source tabulate"
  267.   '(&rest name))
  268.  
  269. (define (keep . kinds)
  270.   (let ((port (command-output)))
  271.     (if (null? kinds)
  272.     (for-each (lambda (kind)
  273.             (if (not (eq? kind 'table))
  274.             (begin
  275.               (display (if ((debug-flag-accessor kind))
  276.                        "+ " "- ")
  277.                    port)
  278.               (display kind port)
  279.               (newline port))))
  280.           debug-flag-names)
  281.     (for-each (lambda (kind)
  282.             (if (and (memq kind debug-flag-names)
  283.                  (not (eq? kind 'table)))
  284.             ((debug-flag-modifier kind) #t)
  285.             (write-line "Unrecognized debug flag"
  286.                     port)))
  287.           kinds))))
  288.  
  289.  
  290. ; Collect some garbage
  291.  
  292. (define (collect)
  293.   (let ((port (command-output))
  294.     (before (memory-status memory-status-option/available #f)))
  295.     ((structure-ref primitives collect))
  296.     (let ((after (memory-status memory-status-option/available #f)))
  297.       (display "Before: " port)
  298.       (write before port)
  299.       (display " words free in semispace")
  300.       (newline)
  301.       (display "After:  " port)
  302.       (write after port)
  303.       (display " words free in semispace")
  304.       (newline))))
  305.  
  306. (define memory-status-option/available (enum memory-status-option available))
  307.  
  308. (define-command-syntax 'collect "" "invoke the garbage collector" '())
  309.  
  310. ; Undefined (this is sort of pointless now that NOTING-UNDEFINED-VARIABLES
  311. ; exists)
  312. ;
  313. ;(define (show-undefined-variables)
  314. ;  (let ((out (command-output))
  315. ;        (undef (undefined-variables (environment-for-commands))))
  316. ;    (if (not (null? undef))
  317. ;        (begin (display "Undefined: " out)
  318. ;               (write undef out)
  319. ;               (newline out)))))
  320. ;
  321. ;(define-command-syntax 'undefined "" "list undefined variables"
  322. ;  '() show-undefined-variables)
  323.  
  324.  
  325.  
  326. ; Trace and untrace
  327.  
  328. (define traced-procedures
  329.   (user-context-accessor 'traced (lambda () '())))
  330. (define set-traced-procedures!
  331.   (user-context-modifier 'traced))
  332.  
  333. (define (trace . names)
  334.   (if (null? names)
  335.       (let ((port (command-output)))
  336.     (write (map car (traced-procedures)) port)
  337.     (newline port))
  338.       (for-each trace-1 names)))
  339.  
  340. (define-command-syntax 'trace "<name> ..."
  341.   "trace calls to given procedure(s)"
  342.   '(&rest name))
  343.  
  344. (define (untrace . names)
  345.   (if (null? names)
  346.       (for-each untrace-1 (map car (traced-procedures)))
  347.       (for-each untrace-1 names)))
  348.  
  349. (define-command-syntax 'untrace "<name> ..." "stop tracing calls"
  350.   '(&rest name))
  351.  
  352. ; Trace internals
  353.  
  354. (define (trace-1 name)
  355.   (let* ((env (environment-for-commands))
  356.      (proc (environment-ref env name))
  357.      (traced (make-traced proc name)))
  358.     (set-traced-procedures!
  359.         (cons (list name traced proc env)
  360.               (traced-procedures)))
  361.     (environment-define! env name traced))) ;was environment-set!
  362.        
  363. ; Should be doing clookup's here -- avoid creating new locations
  364.  
  365. (define (untrace-1 name)
  366.   (let ((probe (assq name (traced-procedures))))
  367.     (if probe
  368.     (let* ((traced (cadr probe))
  369.            (proc (caddr probe))
  370.            (env (cadddr probe)))
  371.       (if (eq? (environment-ref env name) traced)
  372.           (environment-set! env name proc)
  373.           (let ((out (command-output)))
  374.         (display "Value of " out)
  375.         (write name out)
  376.         (display " changed since ,trace; not restoring it." out)
  377.         (newline out)))
  378.       (set-traced-procedures!
  379.               (filter (lambda (x)
  380.                 (not (eq? (car x) name)))
  381.                   (traced-procedures))))
  382.     (write-line "?" (command-output)))))
  383.  
  384. (define (make-traced proc name)
  385.   (lambda args
  386.     (apply-traced proc name args)))
  387.  
  388. (define *trace-depth* 8)
  389. (define (apply-traced proc name args)
  390.   (let ((port (command-output)))
  391.     (dynamic-wind
  392.      (lambda ()
  393.        (display "[" port))
  394.      (lambda ()
  395.        (let-fluids $write-length *trace-depth*
  396.      $write-depth *trace-depth*
  397.      (lambda ()
  398.        (display "Enter " port)
  399.        (write-carefully (error-form name args) port)
  400.        (newline port)))
  401.        (call-with-values (lambda ()
  402.                (apply proc args))
  403.      (lambda results
  404.        (let-fluids $write-length *trace-depth*
  405.          $write-depth (- *trace-depth* 1)
  406.          (lambda ()
  407.            (display " Leave " port)
  408.            (write-carefully name port)
  409.            (for-each (lambda (result)
  410.                (display " " port)
  411.                (write-carefully (value->expression result) port))
  412.              results)))
  413.        (apply values results))))
  414.      (lambda ()
  415.        (display "]" port)
  416.        (newline port)))))
  417.  
  418. ; Timer stuff.
  419.  
  420. (define ptime (structure-ref primitives time))
  421.  
  422. (define (time command)
  423.   (let* ((thunk (if (eq? (car command) 'run)
  424.             (evaluate `(lambda () ,(cadr command))
  425.                   (environment-for-commands))
  426.             (lambda () (execute-command command))))
  427.      (start-time (ptime time-option/run-time #f)))
  428.     (call-with-values thunk
  429.       (lambda results
  430.     (let* ((stop-time (ptime time-option/run-time #f))
  431.            (dt (- stop-time start-time))
  432.            (units-per-second (ptime time-option/ticks-per-second #f))
  433.            (delta (quotient (* dt 100) units-per-second))
  434.            (port (command-output)))
  435.       (display "Run time: " port)
  436.       (write-hundredths delta port)
  437.       (display " seconds" port)
  438.       (newline port)
  439.       (set-focus-values! results))))))
  440.  
  441. (define time-option/run-time (enum time-option run-time))
  442. (define time-option/ticks-per-second (enum time-option ticks-per-second))
  443.  
  444. (define (write-hundredths n port)
  445.   (write (quotient n 100) port)
  446.   (write-char #\. port)
  447.   (let ((r (remainder n 100)))
  448.     (if (< r 10)
  449.     (write-char #\0 port))
  450.     (write r port)))
  451.  
  452. (define-command-syntax 'time "<command>" "measure execution time"
  453.   '(command))
  454.  
  455. ; Support for stuffing things from Emacs.
  456.  
  457. (define-command-syntax 'from-file #f #f    ;"<filename>" "editor support"
  458.   '(&opt filename))
  459.  
  460. (define-command-syntax 'end #f #f
  461.   '())
  462.  
  463. (define (from-file . maybe-filename)
  464.   (let* ((filename (if (null? maybe-filename) #f (car maybe-filename)))
  465.      (env (let ((probe (if filename
  466.                    (get-file-environment filename)
  467.                    #f))
  468.             (c (environment-for-commands)))
  469.         (if (and probe (not (eq? probe c)))
  470.             (let ((port (command-output)))
  471.               (newline port)
  472.               (display filename port)
  473.               (display " => " port)
  474.               (write probe port)
  475.               (display " " port) ;dots follow
  476.               probe)
  477.             c)))
  478.      (in (command-input)))
  479.     (let ((forms (let recur ()
  480.            (let ((command (read-command #f #t in)))
  481.              (if (eof-object? command)
  482.              '()
  483.              (case (car command)
  484.                ((end) '())
  485.                ((#f run) (cons (cadr command) (recur)))
  486.                (else
  487.                 (error "unusual command in ,from-file ... ,end"
  488.                    command))))))))
  489.       (if (package? env)
  490.       (with-interaction-environment env
  491.         (lambda ()
  492.           (noting-undefined-variables env
  493.         (lambda ()
  494.           (eval-from-file forms env (if (null? maybe-filename)
  495.                         #f
  496.                         (car maybe-filename)))))))
  497.       (for-each (lambda (form) (eval form env)) ;Foo
  498.             env)))))
  499.  
  500.  
  501. ; Filename -> environment map.
  502.  
  503. (define file-environments
  504.   (user-context-accessor 'file-environments (lambda () '())))
  505.  
  506. (define set-file-environments!
  507.   (user-context-modifier 'file-environments))
  508.  
  509. (define (forget-file-environments)
  510.   (set-file-environments! '()))
  511.  
  512. (define (note-file-environment! filename env)
  513.   (if (user-context)
  514.       (let* ((translated ((structure-ref filenames translate) filename))
  515.          (envs (file-environments))
  516.          (probe (or (assoc filename envs) ;What to do?
  517.             (assoc translated envs))))
  518.     (if probe
  519.         (if (not (eq? env (weak-pointer-ref (cdr probe))))
  520.         (let ((port (command-output)))
  521.           (newline port)
  522.           (display "Changing default package for file " port)
  523.           (display filename port)
  524.           (display " from" port)
  525.           (newline port)
  526.           (write (weak-pointer-ref (cdr probe)) port)
  527.           (display " to " port)
  528.           (write env port)
  529.           (newline port)
  530.           (set-cdr! probe (make-weak-pointer env))))
  531.         (set-file-environments!
  532.          (cons (cons filename (make-weak-pointer env))
  533.            envs))))))
  534.  
  535. (define (get-file-environment filename)
  536.   (let ((probe (assoc filename (file-environments)))) ;translate ?
  537.     (if probe
  538.     (weak-pointer-ref (cdr probe))
  539.     #f)))
  540.  
  541. (set-fluid! $note-file-package note-file-environment!)
  542.  
  543. (define-command-syntax 'forget "<filename>"
  544.   "forget file/package association"
  545.   '(filename))
  546.  
  547. (define (forget filename)
  548.   (note-file-environment! filename #f))
  549.  
  550. ; ,bound? <name>
  551.  
  552. (define-command-syntax 'bound? "<name>"
  553.   "display binding of name, if any"
  554.   '(name))
  555.  
  556. (define (bound? name)
  557.   (let ((port (command-output))
  558.     (probe (package-lookup (environment-for-commands) name)))
  559.     (if probe
  560.     (begin (display "Bound to " port)
  561.            (write probe)
  562.            (newline port))
  563.     (write-line "Not bound" port))))
  564.  
  565. ; ,expand <form>
  566.  
  567. (define-command-syntax 'expand "[<form>]"
  568.   "macro-expand a form"
  569.   '(&opt expression))
  570.  
  571. (define (expand . maybe-exp)
  572.   (let ((exp (if (null? maybe-exp) (focus-object) (car maybe-exp)))
  573.     (env (package->environment (environment-for-commands))))
  574.     (set-focus-object!
  575.      (schemify (classify exp env) env))))
  576.